//OpenCollar - updateManager - 3.380
// First generation updater for the SubAO and Owner Hud.  
// Plans for this script: (3.5) -> Merge with collar updates from issue 760

//enter here the short script name of the script that manages resets/setting run of scripts
string resetScript = "update";

integer UPDATE = 10001;
integer updateChildPin = 4711;
integer updatehandle;
string newversion;
list itemTypes;

integer checked = FALSE;//set this to true after checking version


debug(string message)
{
    //llOwnerSay("DEBUG " + llGetScriptName() + ": " + message);
}

// Standaridized setup of channels and name.
integer updateChannel;
DoChannelSetup()
{   
    list params = llParseString2List(llGetObjectDesc(), ["~"], []);
    string updateName = llList2String(params, 0);
     
    if (llSubStringIndex(updateName,"OpenCollar Sub AO") == 0)
        updateChannel = -7483211;
    else if (llSubStringIndex(updateName,"OpenCollar Owner Hud") == 0)
        updateChannel = -7483212;
    else if (llSubStringIndex(updateName,"OpenCollar") == 0)
        updateChannel = -7483210; 
}

SafeRemoveInventory(string item)
{
    if (llGetInventoryType(item) != INVENTORY_NONE)
    {
        llRemoveInventory(item);
    }
}

SafeResetOther(string scriptname)
{
    if (llGetInventoryType(scriptname) == INVENTORY_SCRIPT)
    {
            llResetOtherScript(scriptname);
            llSetScriptState(scriptname, TRUE);        
    }
}

integer isOpenCollarScript(string name)
{
    name = llGetSubString(name, 0, 9);
    if (name == "OpenCollar")
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

StopAllScripts()
{
    // set all scripts in me to NOT RUNNING
    integer n;
    for (n = 0; n < llGetInventoryNumber(INVENTORY_SCRIPT); n++)
    {
        string script = llGetInventoryName(INVENTORY_SCRIPT, n);
        if (script != llGetScriptName())
        {
            if (llGetInventoryType(script) == INVENTORY_SCRIPT)
            {
                if(llGetScriptState(script))
                {
                    llSetScriptState(script, FALSE);
                } 
            }
            else
            { //somehow we got passed a script we can't find.  Wait a sec and try again
                if (llGetInventoryType(script) == INVENTORY_SCRIPT)
                {
                    llSetScriptState(script, FALSE);        
                }        
                else
                {
                    llWhisper(DEBUG_CHANNEL, "Could not set " + script + " to not running.");
                }
            }
        }
    }
}
DeleteOld(list toDelete)
{
    integer i;
    for (i = 0; i < llGetListLength(toDelete); i++)
    {
        string delName = llList2String(toDelete, i);
        integer index = llSubStringIndex(delName, "*");
        if (index == -1)
        {
            SafeRemoveInventory(delName);
        }
        else
        {
            integer n;
            string partName = llGetSubString(delName, 0, index - 1);
            for (n = 0; n < llGetInventoryNumber(INVENTORY_SCRIPT); n++)
            {
                delName = llGetInventoryName(INVENTORY_SCRIPT, n);
                if (llGetSubString(delName, 0, index -1) == partName)
                {
                    SafeRemoveInventory(delName);
                    // ok this looks nonsense but else i keep missing scripts:
                    n = 0;
                }
            }
        }
    }
    llWhisper(updateChannel, "deletedOld");
}

DeleteItems(list toDelete)
{
    integer type = (integer)llList2String(toDelete, 0);
    toDelete = llDeleteSubList(toDelete, 0,0);
    integer i;
    if(type == INVENTORY_SCRIPT)
    {//handle replacing scripts.  These are different from other inventory because they're versioned.
        list oldScripts;
        list newScripts;
        string fullScriptName;
        string shortScriptName;
        
        //make list of scripts that we'll be receiving from updater, w/o version numbers
        for(i = 0; i < llGetListLength(toDelete); i++)
        {
            fullScriptName = llList2String(toDelete, i);
            shortScriptName = llGetSubString(fullScriptName, 0, llStringLength(fullScriptName) - 6);
            newScripts += [shortScriptName];
        }
        
        //make strided list of scripts in inventory, in form versioned,nonversioned
        for(i = 0; i < llGetInventoryNumber(INVENTORY_SCRIPT); i ++)
        {
            fullScriptName = llGetInventoryName(type, i);
            shortScriptName = llGetSubString(fullScriptName, 0, llStringLength(fullScriptName) - 6);
            oldScripts += [fullScriptName, shortScriptName];
        }
        
        //loop through new scripts.  Delete old, superseded ones
        for(i = 0; i < llGetListLength(newScripts); i++)
        {
            shortScriptName = llList2String(newScripts, i);
            integer foundAt = llListFindList(oldScripts, [shortScriptName]);
            if(foundAt != -1)
            {
                fullScriptName = llList2String(oldScripts, foundAt -1);
                if(fullScriptName != llGetScriptName())
                {
                    debug("deleting " + fullScriptName);
                    SafeRemoveInventory(fullScriptName);
                }
            }
        }
    }
    else
    {
        for (i = 0; i < llGetListLength(toDelete); i++)
        {
            string delName = llList2String(toDelete, i);
            if(llGetInventoryType(delName) != -1)
            {
                SafeRemoveInventory(delName);
            }
        }
    }
    integer index = llListFindList(itemTypes, [(string)type]); // should always be 0
    itemTypes = llDeleteSubList(itemTypes, index, index);
    if(llGetListLength(itemTypes))
    {
        llWhisper(updateChannel, "giveList|" + llList2String(itemTypes, 0));
    }
    else
    {
        debug("ready to receive");
        llWhisper(updateChannel, "ready to receive");
    }
}

FinalizeUpdate()
{
    debug("finalize started");
    llSetRemoteScriptAccessPin(0);
    integer i;
    string fullScriptName;
    integer scriptNumber = llGetInventoryNumber(INVENTORY_SCRIPT);
    llWhisper(updateChannel, "restarting scripts");
    //rename the collar and its description to the new version
    string collarName = llGetObjectName();
    string collarDesc = llGetObjectDesc();
    list lname = llParseString2List(collarName, [" "],[]);
    list ldesc = llParseString2List(collarDesc, ["~"], []);  
    for (i = 0; i < llGetListLength(lname); i++)
    {
        if (llList2String(ldesc, 1) == llList2String(lname, i))
        {
            lname = llListReplaceList(lname, [newversion], i, i);
            string newname = llDumpList2String(lname, " ");
            llSetObjectName(newname);
        }
    }
    ldesc = llListReplaceList(ldesc, [newversion], 1, 1);
    llSetObjectDesc(llDumpList2String(ldesc, "~"));
    debug("reseting scripts");
    //start the scripts 
    for (i = 0; i < scriptNumber; i++)
    {   //reset all other OpenCollar scripts
        fullScriptName = llGetInventoryName(INVENTORY_SCRIPT, i);
        debug("reseting: " + fullScriptName);
        if(isOpenCollarScript(fullScriptName) && fullScriptName != llGetScriptName())
        {
            SafeResetOther(fullScriptName);
        }
    }
    debug("done, sending finished and removing self");
    llSleep(1.0);
    llWhisper(updateChannel, "finished");
    llRemoveInventory(llGetScriptName());
}

default 
{
    state_entry() 
    {
        if( llGetStartParameter() == 42)
        {
            DoChannelSetup();           
            debug("started with startParam 42.");
            StopAllScripts();
            updatehandle = llListen(updateChannel, "", "", "");
            llMessageLinked(LINK_ALL_OTHERS, UPDATE, "prepare", NULL_KEY);
            llWhisper(updateChannel, "Manager Ready");
        }
    }

    listen(integer channel, string name, key id, string message) 
    {
        if (llGetOwnerKey(id) == llGetOwner())
        {
            list temp = llParseString2List(message, [","], []);
            string command0 = llList2String(temp,0);
            string command1 = llList2String(temp,1);
            if (command0 == "delete")
            {
                list thingstodelete = llDeleteSubList(temp, 0, 0);
                debug("deleting: " + llDumpList2String(thingstodelete, ","));
                DeleteOld(thingstodelete);
                //send a message to child prims
                llMessageLinked(LINK_ALL_OTHERS, UPDATE, "prepare", "");
            }
            else if(command0 == "toupdate")
            {
                llSetTimerEvent(0.0);
                itemTypes = llList2List(temp, 1, -1);
                llWhisper(updateChannel, "giveList|" + llList2String(itemTypes, 0));
            }
            else if(command0 == "items")
            {
                DeleteItems(llDeleteSubList(temp, 0, 0));
            }
            else if(command0 == "version")
            {
                newversion = llGetSubString((string)llList2Float(temp, 1), 0, 4);
                llListenRemove(updatehandle);
                FinalizeUpdate();
            }
        }
    }
}